import {
    AnyError,
    CollectionInfo,
    DeleteResult,
    InsertManyResult,
    MongoClient
} from "mongodb";

interface IRecord {
    collection: string,
    documents: Array<object>
}

export class MongoDB {
    url: string;
    db_name: string;
    client: MongoClient;

    constructor() {
        this.db_name = 'grafana'
        this.url = 'mongodb://grafana:JdCJB8s5NccpPhUqcacGcbVd9tGwah5mEmUrG@localhost:19458/' + this.db_name;
    }

    createConnect(): Promise<MongoClient> {
        return MongoClient.connect(this.url)
    }

    closeConnect() {
        this.client?.close()
    }

    saveRecord(record: IRecord): Promise<void | MongoClient> {
        return this.createConnect().then((client: MongoClient) => {
            this.client = !this.client ? client : this.client;
            let db = client.db(this.db_name);
            db.collection(record.collection).insertMany(record.documents, (err: AnyError | undefined,
                                                                           res: InsertManyResult<Document> | undefined) => {
                if (err) throw err;
                client.close();
            });
        });
    }

    cleanCollection(collection: string): Promise<Array<any>> {
        return this.createPromise((db, resolve, reject) => {
            db.collection(collection).deleteMany({}).then((res: DeleteResult) => {
                resolve([]);
            });
        });
    }

    checkCollectionExists(db: any, collection: string, reject: any, callback = (db): void => {
    }) {

        db.listCollections().toArray().then((res: CollectionInfo[]) => {
            let exists = false;
            res.forEach(item => {
                if (collection == item.name) {
                    exists = true;
                    return false;
                }
            })
            if (exists) {
                callback(db);
            } else {
                reject('No Such Container');
            }

        })

    }


    deleteDocumentFromCollection(collection: string, documents_number: Array<number>): Promise<Array<any>> {
        return this.createPromise((db, resolve, reject) => {
            this.checkCollectionExists(db, collection, reject, (db) => {
                let num = 1;
                db.collection(collection).find({}).forEach(doc => {
                    if (documents_number.indexOf(num) >= 0) {
                        db.collection(collection).deleteOne({_id: doc._id});
                    }
                    num++;
                });
                resolve([])
            })
        })
    }


    getRecord(collection: string): Promise<Array<any>> {
        return this.createPromise((db, resolve, reject) => {
            this.checkCollectionExists(db, collection, reject, (db) => {
                db.collection(collection).find({}, {projection: {_id: 0}}).toArray((err, res) => {
                    return resolve(res);
                });
            });
        })
    }

    getList(): Promise<Array<any>> {
        return this.createPromise((db, resolve, reject) => {
            db.listCollections().toArray().then((res: CollectionInfo[]) => {
                let list = res.map(item => item.name)
                resolve(list);
            })
        })
    }

    createPromise(callback = (db, resolve, reject) => {
    }): Promise<Array<any>> {
        return new Promise((resolve, reject) => {
            this.createConnect().then((client: MongoClient) => {
                this.client = !this.client ? client : this.client;
                let db = client.db(this.db_name);
                callback(db, resolve, reject);
            })
        });
    }

}
